//
//  SerialPort.h
//  Calibration
//
//  Created by ViKing Lai on 2018/1/24.
//  Copyright © 2018年 ViKing Lai. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <termios.h>
#import <sys/ioctl.h>

#define MAX_READ_BUFFER  (8192UL)

#define CTRL_Q  (0x11)
#define CTRL_S  (0x13)

typedef NS_ENUM(NSUInteger, Parity)
{
    eParityNone = 0,
    eParityOdd = 1,
    eParityEven = 2,
    eParityDefault = eParityNone,
    eParityInvalid
};

typedef NS_ENUM(NSUInteger, StopBits)
{
    eStopBitsOne = 1,
    eStopBitsTwo = 2,
    eStopBitsDefault = eStopBitsOne,
    eStopBitsInvalid
};

typedef NS_ENUM(NSUInteger, BaudRate)
{
    eBaudrate50      = B50,
    eBaudrate75      = B75,
    eBaudrate110     = B110,
    eBaudrate134     = B134,
    eBaudrate150     = B150,
    eBaudrate200     = B200,
    eBaudrate300     = B300,
    eBaudrate600     = B600,
    eBaudrate1200    = B1200,
    eBaudrate1800    = B1800,
    eBaudrate2400    = B2400,
    eBaudrate4800    = B4800,
    eBaudrate9600    = B9600,
    eBaudrate19200   = B19200,
    eBaudrate38400   = B38400,
    eBaudrate57600   = B57600,
    eBaudrate115200  = B115200,
    eBaudrate230400  = B230400,
#ifdef __linux__
    eBaudrate460800 = B460800,
#endif
    eBaudrateDefault = eBaudrate115200,
    eBaudrateInvalid
};

typedef NS_ENUM(NSInteger, DataBits)
{
    eDataBits5 = 5,
    eDataBits6 = 6,
    eDataBits7 = 7,
    eDataBits8 = 8,
    eDataBitsDefault = eDataBits8,
    eDataBitsInvalid = -1
};

typedef NS_ENUM(NSInteger, FlowControls)
{
    eFlowControlHard,
    eFlowControlSoft,
    eFlowControlNone,
    eFlowControlDefault = eFlowControlNone,
    eFlowControlInvalid
};

typedef NS_ENUM(NSInteger, InputMode)
{
    /** line input mode(the input data will be put in a buffer until received character '\\r' or '\\n') */
    eLineMode = ICANON | ECHO | ECHOE,
    /** origin input mode(the input data will be transmit immediately with no processing) */
    eOriginMode = ~eLineMode,
};

@class HiperTimer;
@class SerialDevice;

@protocol SerialPortDelegate;

@interface SerialPort : NSObject

/*!
 *@abstract 获取或设置委托对象
 */
@property (nonatomic) id<SerialPortDelegate> delegate;

/*!
 *@abstract 获取串口是否打开
 */
@property (readonly)        BOOL            isOpen;
/*!
 *@abstract 获取dylib的软件
 */
@property (readonly)        NSString        *version;
/*!
 *@abstract 获取最后一次的错误信息
 */
@property (readonly)        NSString        *lastErrInfo;
/*!
 *@abstract 获取通信使用的串口路径名
 */
@property (readonly)        NSString        *portname;
/*!
 *@abstract 获取或设置换行符
 */
@property (readwrite, copy) NSString        *newLine;
/*!
 *@abstract 获取或设置串口的波特率
 */
@property (nonatomic)       BaudRate        baudrate;
/*!
 *@abstract 获取或设置串口的数据位
 */
@property (nonatomic)       DataBits        databits;
/*!
 *@abstract 获取或设置串口的停止位
 */
@property (nonatomic)       StopBits        stopbits;
/*!
 *@abstract 获取或设置串口的奇偶校验位
 */
@property (nonatomic)       Parity          parity;
/*!
 *@abstract 获取或设置串口流控制位
 */
@property (nonatomic)       FlowControls    flowControls;
/*!
 *@abstract 获取或设置串口的输入模式
 */
@property (nonatomic)       InputMode       inputMode;

/*!
 *@abstract 获取当前计算机的串行端口名称数组
 */
+ (NSArray *)portNames;
/*!
 *@abstract         使用串口名/dev/usbserial-xx初始化串口
 *@param portname   串口路径名
 */
- (id)initWithPath:(NSString *)portname;
/*!
 *@abstract         使用串口名/dev/usbserial-xx初始化串口
 *@param portname   串口路径名
 *@param baudrate   波特率
 *@param databits   数据位
 *@param stopbits   停止位
 *@param parity     奇偶校验位
 *@param flowControls 流控制位
 */
- (id)initWithPath:(NSString *)portname
          baudrate:(BaudRate)baudrate
          databits:(DataBits)databits
          stopbits:(StopBits)stopbits
            parity:(Parity)parity
      flowControls:(FlowControls)flowControls;
/*!
 *@abstract         打开串口
 */
- (BOOL)open;
/*!
 *@abstract         打开串口
 *@param portname   串口路径名
 *@return           成功打开串口则返回YES，反之返回NO
 */
- (BOOL)open:(NSString *)portname;
/*!
 *@abstract         使用串口名/dev/usbserial-xx初始化串口，并打开串口
 *@param portname   串口路径名
 *@param baudrate   波特率
 *@param databits   数据位
 *@param stopbits   停止位
 *@param parity     奇偶校验位
 *@param flowControls 流控制位
 *@return           成功打开串口则返回YES，反之返回NO
 */
- (BOOL)open:(NSString *)portname
    baudrate:(BaudRate)baudrate
    databits:(DataBits)databits
    stopbits:(StopBits)stopbits
      parity:(Parity)parity
 flowControls:(FlowControls)flowControls;
/*!
 *@abstract         关闭串口
 *@return           成功关闭串口则返回YES，反之返回NO
 */
- (BOOL)close;
/*!
 *@abstract         获取输入缓冲区中的字节数
 *@return           缓冲区中字节数
 */
- (NSUInteger)bytesToRead;
/*!
 *@abstract         向串口写入一行数据，默认编码UTF-8
 *@param data       需要写入的数据（字符串形式）
 */
- (void)writeLine:(NSString *)data;
/*!
 *@abstract         向串口写入数据，默认编码UTF-8
 *@param data       需要写入的数据（字符串形式）
 */
- (void)write:(NSString *)data;
/*!
 *@abstract         向串口写入NSData类型数据
 *@param data       需要写入的数据（字符串形式）
 *@param encoding   字符编码格式
 */
- (void)write:(NSString *)data encoding:(NSStringEncoding)encoding;
/*!
 *@abstract         向串口写入NSData类型数据
 *@param data       需要写入的数据（NSData）
 */
- (void)writeData:(NSData *)data;
/*!
 *@abstract         将指定数量的字节写入输出缓冲区中的指定偏移量处
 *@param bytes      将输出写入的字节数组
 *@param offset     缓冲区数组中开始写入的偏移量
 *@param count      要写入的字节数
 */
- (void)writeBytes:(const char *)bytes
            offset:(NSInteger)offset
             count:(NSInteger)count;
/*!
 *@abstract         读取一个字符
 *@return           读取到的字符
 */
- (char)readChar;
/*!
 *@abstract         读取一行数据
 *@return           读取到的数据
 */
- (NSString *)readLine;
/*!
 *@abstract         读取输入缓冲区中所有立即可用的字节
 *@return           读取到的数据
 */
- (NSString *)readExisting;
/*!
 *@abstract         一直读取到输入缓冲区中的指定 value 的字符串
 *@param value      指示读取操作停止位置的值
 *@param timeout    超时时间
 *@param restTime   反应时间
 *@return           读取到的数据
 */
- (NSString *)readTo:(NSString *)value
             timeout:(NSUInteger)timeout
        restInterval:(NSUInteger)restTime;
/*!
 *@abstract         一直读取到输入缓冲区中的指定 value 的字符串
 *@param value      指示读取操作停止位置的值
 *@param timeout    超时时间
 *@param restTime   反应时间
 *@param block      数据处理block
 *@return           读取到的数据
 */
- (NSData *)readTo:(NSString *)value
           timeout:(NSUInteger)timeout
      restInterval:(NSUInteger)restTime
        usingBlock:(void (^)(NSData *data))block;
/*!
 *@abstract         从串口中读取指定长度的字节
 *@param buffer     将读取的数据写入到其中的字节数组
 *@param offset     缓冲区数组中开始写入的偏移量
 *@param count      要读取的字节数
 *@return           读取的字节数
 */
- (NSInteger)readBytes:(char [])buffer
                offset:(NSInteger)offset
                 count:(NSInteger)count;
/*!
 *@abstract         丢弃来自串行驱动程序的接收缓冲区的数据
 */
- (BOOL)discardInBuffer;
/*!
 *@abstract         丢弃来自串行驱动程序的传输缓冲区的数据
 */
- (BOOL)discardOutBuffer;
/*!
 *@abstract         丢弃来自串口驱动程序缓冲区的数据
 */
- (BOOL)discardBuffer;

@end

// protocol
@protocol SerialPortDelegate <NSObject>

@optional

/*!
 *  Called when a serial port is successfully opened.
 *
 *  @param serialPort The `SerialPort` instance representing the port that was opened.
 */
- (void)serialPortWasOpened:(SerialPort *)serialPort;
/*!
 *  Called when a serial port was closed (e.g. because `-close`) was called.
 *
 *  When an SSerialPort instance is closed, its queued requests are cancelled. This is done _after_ the call to `-serialPortWasClosed:`.
 *
 *  @param serialPort The `ORSSerialPort` instance representing the port that was closed.
 */
- (void)serialPortWasClosed:(SerialPort *)serialPort;
/*!
 *  Called when an error occurs during an operation involving a serial port.
 *
 *	This method is always used to report errors. No `SerialPort` methods
 *  take a passed in `NSError **` reference because errors may occur asynchonously,
 *  after a method has returned.
 *
 *  @param serialPort The `ORSSerialPort` instance for the port
 *  @param error      An `NSError` object containing information about the error.
 */
- (void)serialPort:(SerialPort *)serialPort didEncounterError:(NSString *)error;
/*!
 *  Called any time new data is received by the serial port from an external source.
 *
 *  @param serialPort The `SerialPort` instance representing the port that received `data`.
 *  @param data       An `NSData` instance containing the data received.
 */
- (void)serialPort:(SerialPort *)serialPort didReceiveData:(NSData *)data;
/*!
 *  Called any time new data is receiving by the serial port from an external source.
 *
 *  @param serialPort The `SerialPort` instance representing the port that received `data`.
 *  @param data       An `NSData` instance containing the data receiving.
 */
- (void)serialPort:(SerialPort *)serialPort doingReceiveData:(NSData *)data;

@end
